﻿using System;
using System.Collections.Generic;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace UI.Dendrogram
{
    public class BinaryHierarchicalData
    {
        public int ID { get; set; }
        public string Label { get; set; }
        public double Distance { get; set; }
        public object Tag { get; set; }
        private BinaryHierarchicalData _Parent;
        public BinaryHierarchicalData Parent
        {
            get
            {
                return _Parent;
            }
            set
            {
                this._Parent = value;
            }
        }

        private BinaryHierarchicalData _LeftChild;
        public BinaryHierarchicalData LeftChild
        {
            get
            {
                return _LeftChild;
            }
            set
            {
                this._LeftChild = value;
                if (this._LeftChild != null)
                    this._LeftChild.Parent = this;
            }
        }

        private BinaryHierarchicalData _RightChild;
        public BinaryHierarchicalData RightChild
        {
            get
            {
                return _RightChild;
            }
            set
            {
                this._RightChild = value;
                if (this._RightChild !=null)
                this._RightChild.Parent = this;
            }
        }

        private LeafData _LeftLeaf;
        public LeafData LeftLeaf
        {
            get
            {
                return _LeftLeaf;
            }
            set
            {
                this._LeftLeaf = value;
                if (this._LeftLeaf!=null)
                this._LeftLeaf.Parent = this;
            }
        }

        private LeafData _RightLeaf;
        public LeafData RightLeaf
        {
            get
            {
                return _RightLeaf;
            }
            set
            {
                this._RightLeaf = value;
                if (this._RightLeaf!=null)
                this._RightLeaf.Parent = this;
            }
        }

        public BinaryHierarchicalData(int id, string label, double distance, object tag)
        {
            this.ID = id;
            this.Label = label;
            this.Distance = distance;
            this.Tag = tag;

            this.Parent = null;
            this.LeftChild = null;
            this.RightChild = null;
            this.LeftLeaf = null;
            this.RightLeaf = null;
        }

        public BinaryHierarchicalData(BinaryHierarchicalData parent, bool isLeft, 
            int id, string label, double distance, object tag)
            :this(id,label,distance,tag)
        {
            this.Parent = parent;
            if (this.Parent != null)
            {
                if (isLeft)
                    this.Parent.LeftChild = this;
                else
                    this.Parent.RightChild = this;
            }
        }

        public static BinaryHierarchicalData Merge(
            int parentID, string parentLabel, double parentDistance, object parentTag,
            BinaryHierarchicalData left, BinaryHierarchicalData right)
        {
            BinaryHierarchicalData parent=new BinaryHierarchicalData(parentID,parentLabel,parentDistance,parentTag);
            parent.LeftChild = left;
            parent.RightChild = right;
            left.Parent = parent;
            right.Parent = parent;
            return parent;
        }

        public int ChildCount
        {
            get
            {
                int childCount = 0;
                if(this.LeftChild !=null)
                {
                    childCount += (1+this.LeftChild.ChildCount);
                }
                if(this.RightChild !=null)
                {
                    childCount += (1+this.RightChild.ChildCount);
                }
                return childCount;
            }
        }

        public List<BinaryHierarchicalData> Children
        {
            get
            {
                List<BinaryHierarchicalData> children=new List<BinaryHierarchicalData>();
                if(this.LeftChild !=null)
                {
                    children.Add(this.LeftChild);
                    List<BinaryHierarchicalData> grandChildren = this.LeftChild.Children;
                    if(grandChildren !=null && grandChildren.Count>0)
                        children.AddRange(grandChildren);
                }
                if(this.RightChild !=null)
                {
                    children.Add(this.RightChild);
                    List<BinaryHierarchicalData> grandChildren = this.RightChild.Children;
                    if(grandChildren !=null && grandChildren.Count>0)
                        children.AddRange(grandChildren);
                }
                return children;
            }
        }

        public double DistanceToRoot
        {
            get
            {
                double distance = this.Distance;
                if(this.Parent !=null)
                    distance += this.Parent.DistanceToRoot;
                return distance;
            }
        }

        public int Depth
        {
            get
            {
                int leftDepth = 1;
                int rightDepth = 1;
                if(this.LeftChild !=null)
                {
                    leftDepth += this.LeftChild.Depth;
                }
                if(this.RightChild !=null)
                {
                    rightDepth += this.RightChild.Depth;
                }
                return Math.Max(leftDepth, rightDepth);
            }
        }
    }
}
